/*
 * Copyright 2008 Les Hazlewood
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.pojodm.util;

public class Period {

    public static final long MILLISECOND = 1;
    public static final long SECOND = MILLISECOND * 1000;
    public static final long MINUTE = SECOND * 60;
    public static final long HOUR = MINUTE * 60;
    public static final long DAY = HOUR * 24;
    public static final long WEEK = DAY * 7;
    public static final long MONTH = (long) (DAY * 30.4368499);
    public static final long YEAR = SECOND * 31556926; //little more accurate than DAY * 365 because of leap years.
    public static final long DECADE = YEAR * 10;
    public static final long CENTURY = YEAR * 100;
    public static final long MILLENIUM = YEAR * 1000;

    private long millis = 0;

    Period() {
    }

    Period(long millis) {
        if (millis < 0l) {
            throw new IllegalArgumentException("All periods must have a non-negative value (it doesn't make " +
                    "sense to have a negative period of time).");
        }
        this.millis = millis;
    }

    public long getMillenia() {
        return millis / MILLENIUM;
    }

    public long getCenturies() {
        return millis / CENTURY;
    }

    public long getDecades() {
        return millis / DECADE;
    }

    public long getYears() {
        return millis / YEAR;
    }

    public long getMonths() {
        return millis / MONTH;
    }

    public long getDays() {
        return millis / DAY;
    }

    public long getMinutes() {
        return millis / MINUTE;
    }

    public long getSeconds() {
        return millis / SECOND;
    }

    public long getMillis() {
        return millis;
    }

    public String toString() {
        return toString(false);
    }

    public String toString(boolean verbose) {

        //Man this StringBuffer logic is nasty and should be refactored!  But, it works :/

        long millis = this.millis;
        long result;
        boolean out = false;
        boolean secondsOnly = true;

        StringBuffer sb = new StringBuffer();

        if (millis >= MILLENIUM) {
            result = millis / MILLENIUM;
            millis = millis % MILLENIUM;
            sb.append(result).append(result == 1 ? " millenium" : " millenia");
            out = true;
            secondsOnly = false;
        }

        if (millis >= CENTURY) {
            result = millis / CENTURY;
            millis = millis % CENTURY;
            if (out) {
                sb.append(", ");
            }
            sb.append(result).append(result == 1 ? " century" : " centuries");
            out = true;
            secondsOnly = false;
        } else {
            if (out) {
                sb.append(", 0 centuries");
            }
        }

        if (millis >= YEAR) {
            result = millis / YEAR;
            millis = millis % YEAR;
            if (out) {
                sb.append(", ");
            }
            sb.append(result).append(result == 1 ? " year" : " years");
            out = true;
            secondsOnly = false;
        } else {
            if (out) {
                sb.append(", 0 years");
            }
        }

        if (millis >= MONTH) {
            result = millis / MONTH;
            millis = millis % MONTH;
            if (out) {
                sb.append(", ");
            }
            sb.append(result).append(result == 1 ? " month" : " months");
            out = true;
            secondsOnly = false;
        } else {
            if (out) {
                sb.append(", 0 months");
            }
        }

        if (millis >= DAY) {
            result = millis / DAY;
            millis = millis % DAY;
            if (out) {
                sb.append(", ");
            }
            sb.append(result).append(result == 1 ? " day" : " days");
            out = true;
            secondsOnly = false;
        } else {
            if (out) {
                sb.append(", 0 days");
            }
        }

        if (millis >= HOUR) {
            result = millis / HOUR;
            millis = millis % HOUR;
            if (out) {
                sb.append(", ");
            }
            if (verbose) {
                sb.append(result).append(result == 1 ? " hour" : " hours");
            } else {
                sb.append(result).append(":");
            }
            out = true;
            secondsOnly = false;
        } else {
            if (verbose) {
                if (out) {
                    sb.append(", 0 hours");
                }
            } else {
                if ( out ) {
                    sb.append("0:");
                }
            }
        }

        if (millis >= MINUTE) {
            result = millis / MINUTE;
            millis = millis % MINUTE;
            if (verbose) {
                if (out) {
                    sb.append(", ");
                }
                sb.append(result).append(result == 1 ? " minute" : " minutes");
            } else {
                if ( result < 10 && out ) {
                    sb.append("0");
                }
                sb.append(result).append(":");
            }
            out = true;
            secondsOnly = false;
        } else {
            if (verbose) {
                if (out) {
                    sb.append(", 0 minutes");
                }
            } else {
                if ( out ) {
                    sb.append("00:");
                }
            }
        }


        if (millis >= SECOND) {
            result = millis / SECOND;
            millis = millis % SECOND;
            if (verbose) {
                if (out) {
                    sb.append(", ");
                }
                sb.append(result).append(result == 1 ? " second" : " seconds");
            } else {
                if ( result < 10 && out ) {
                    sb.append("0");
                }
                sb.append(result);
            }
            out = true;
        } else {
            if (verbose) {
                if (out) {
                    sb.append(", 0 seconds");
                }
            } else {
                sb.append("0");
            }
        }

        if (millis >= MILLISECOND) {
            if (verbose) {
                if (out) {
                    sb.append(", ");
                }
                sb.append(millis).append(millis == 1 ? " millisecond" : " milliseconds");
            } else {
                sb.append(".").append(millis);
                if ( secondsOnly ) {
                    sb.append( " seconds" );
                }
            }

        } else {
            if (verbose) {
                if (out) {
                    sb.append(", 0 milliseconds");
                } else {
                    sb.append("0 milliseconds");
                }
            } else {
                if ( secondsOnly ) {
                    sb.append(".0 seconds" );
                }
            }
        }

        return sb.toString();
    }

    public static void main(String[] args) {
        long millis = (MINUTE * 2 ) + (SECOND * 5) + (MILLISECOND * 15);//(MILLENIUM * 5 ) + /*(YEAR * 2) + (MONTH * 3) + (DAY * 30) + (HOUR * 12) + /*(MINUTE * 44) + *(SECOND * 32) + (MILLISECOND * 12);
        Period period = new Period(millis);
        System.out.println(period);
        System.out.println(period.toString(true));
    }
}
